<?php
namespace plugins\aliyuncs\controller;
use cmf\controller\PluginBaseController;
use plugins\aliyuncs\AliyuncsPlugin;
use plugins\aliyuncs\lib\Aliyuncs;
use think\Db;
use think\Request;
use think\Validate;

class AssetController extends PluginBaseController {
	public function getUrl() {

		$oss = new Aliyuncs([]);

		$fileHash = $this->request->param('file_hash');
		$filname = $this->request->param('filename');
		$fileType = $this->request->param('filetype');

		$suffix = cmf_get_file_extension($filname);

		$file = $fileHash . ".{$suffix}";

		$previewUrl = $fileType == 'image' ? $oss->getPreviewUrl($file) : $oss->getFileDownloadUrl($file);
		$url = $fileType == 'image' ? $oss->getImageUrl($file, 'watermark') : $oss->getFileDownloadUrl($file);

		return $this->success('success', null, [
			'url' => $url,
			'preview_url' => $previewUrl,
			'filepath' => $file,
		]);
	}

	/**
	 * [saveFile description]
	 * @return [type] [description]
	 */
	public function saveFile() {
		$userId = cmf_get_current_admin_id();
		$userId = $userId ? $userId : cmf_get_current_user_id();

		if (empty($userId)) {
			$this->error('error');
		}
		$validate = new Validate([
			'filename' => 'require',
			'file_key' => 'require',
		]);

		$data = $this->request->param();

		$result = $validate->check($data);

		if ($result !== true) {
			$this->error($validate);
		}

		$fileKey = $data['file_key'];

		$suffix = cmf_get_file_extension($data['filename']);

		$config = $this->getPlugin()->getConfig();

		$accessKey = $config['accessKey'];
		$secretKey = $config['secretKey'];

		$auth = new Auth($accessKey, $secretKey);

		$client = new Client();

		$encodedEntryURISrc = \Qiniu\base64_urlSafeEncode($config['bucket'] . ':' . $fileKey);
		$encodedEntryURIDest = \Qiniu\base64_urlSafeEncode($config['bucket'] . ':' . $fileKey . ".{$suffix}");

		$signingStr = "/move/{$encodedEntryURISrc}/{$encodedEntryURIDest}";
		$authorization = $auth->signRequest($signingStr, '');

		$url = 'http://rs.qiniu.com/' . $signingStr;

		$response = $client->post($url, null, ['Authorization' => 'QBox ' . $authorization]);

		if ($response->statusCode == 612) {
			$this->error('文件不存在！');
		}

		if ($response->statusCode == 599) {
			$this->error('文件保存失败！');
		}

		$signingStr = "/stat/{$encodedEntryURIDest}";
		$authorization = $auth->signRequest($signingStr, '');

		$url = 'http://rs.qiniu.com/' . $signingStr;

		$response = $client->get($url, ['Authorization' => 'QBox ' . $authorization]);

		if ($response->statusCode != 200) {
			$this->error('操作失败！');
		}

		$fileInfo = $response->json();

		$findAsset = Db::name('asset')->where('file_key', $fileKey)->find();

		if (empty($findAsset)) {

			Db::name('asset')->insert([
				'user_id' => $userId,
				'file_size' => $fileInfo['fsize'],
				'filename' => $data['filename'],
				'create_time' => time(),
				'file_key' => $fileKey,
				'file_path' => $fileKey . ".{$suffix}",
				'suffix' => $suffix,
			]);
		}

		$this->success('success');
	}

	/**
	 * 获取签名
	 */
	public function getSignature() {
		try {
			$userId = cmf_get_current_admin_id();
			$userId = $userId ? $userId : cmf_get_current_user_id();
			if (empty($userId)) {
				return json(['code' => 0, "msg" => "用户未登录!"]);
			}
			$data = $this->request->param();
			if (!isset($data['module']) || empty($data['module'])) {
				return json(['code' => 0, "msg" => "缺少参数!"]);
			}
			$oldSignature = cmf_get_option("oss_sign_" . $data['module']);
			$currentTime = time();
			if (!empty($oldSignature) && $currentTime < $oldSignature['expire']) {
				$ret = ["code" => 1, "msg" => $oldSignature];
				return json($ret);
			}
			//获取配置信息
			$aliyuncsPlugin = new AliyuncsPlugin();
			$config = $aliyuncsPlugin->getConfig();
			if (empty($config)) {
				$ret = ["code" => 0, "msg" => "没有配置OSS信息"];
				return json($ret);
			}

			$id = $config['accessKey'];
			$key = $config['secretKey'];
			$host = $config['protocol'] . '://' . $config['bucket'] . '.' . $config['endpoint'];
			$root = cmf_get_root();
			$root = empty($root) ? '' : '/' . $root;
			$site_domain = cmf_get_domain() . $root;
			$callbackUrl = $site_domain . "/plugin/aliyuncs/asset/ossCallback";

			$callback_param = array('callbackUrl' => $callbackUrl,
				'callbackBody' => 'etag=${etag}&filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}&uid=' . $userId,
				'callbackBodyType' => "application/x-www-form-urlencoded");
			$callback_string = json_encode($callback_param);

			$base64_callback_body = base64_encode($callback_string);
			$now = time();
			$expire = 3600; //设置该policy超时时间是10s. 即这个policy过了这个有效时间，将不能访问
			$end = $now + $expire;
			$expiration = date("Y-m-d\TH:i:s\Z", $end);
			$userId = cmf_get_current_admin_id();
			$userId = !is_numeric($userId) ? 0 : $userId;
			$dir = "upload/" . $data['module'] . "/" . date("Ymd") . "/"; //上传用户目录

			//最大文件大小.用户可以自己设置
			$condition = array(0 => 'content-length-range', 1 => 0, 2 => 1048576000);
			$conditions[] = $condition;

			//表示用户上传的数据,必须是以$dir开始, 不然上传会失败,这一步不是必须项,只是为了安全起见,防止用户通过policy上传到别人的目录
			$start = array(0 => 'starts-with', 1 => '$key', 2 => $dir);
			$conditions[] = $start;

			$arr = array('expiration' => $expiration, 'conditions' => $conditions);
			$policy = json_encode($arr);
			$base64_policy = base64_encode($policy);
			$string_to_sign = $base64_policy;
			$signature = base64_encode(hash_hmac('sha1', $string_to_sign, $key, true));

			$response = array();
			$response['accessid'] = $id;
			$response['host'] = $host;
			$response['policy'] = $base64_policy;
			$response['signature'] = $signature;
			$response['expire'] = $end;
			$response['callback'] = $base64_callback_body;
			//这个参数是设置用户上传指定的前缀
			$response['dir'] = $dir;
			$response['backurl'] = $callbackUrl;
			cmf_set_option("oss_sign_" . $data['module'], $response, true);
			$ret = ['code' => 1, 'msg' => $response];
			return json($ret);

		} catch (\Exception $e) {
			$str = "发生错误: " . date("Y-m-d H:i:s") . "\r\n";
			$str .= "Error: " . $e->getMessage() . "行号: #" . $e->getLine() . "\r\n\r\n";

			file_put_contents("./console.log", $str, FILE_APPEND);
			return json(['code' => 0, 'msg' => $str]);
		}
	}

	//Web直传的回调函数
	public function ossCallback() {
		// return json(['code' => 0, 'msg' => "测试!"]);
		try {
			// 1.获取OSS的签名header和公钥url header
			$authorizationBase64 = "";
			$pubKeyUrlBase64 = "";
			/*
				     * 注意：如果要使用HTTP_AUTHORIZATION头，你需要先在apache或者nginx中设置rewrite，以apache为例，修改
					 * 配置文件/etc/httpd/conf/httpd.conf(以你的apache安装路径为准)，在DirectoryIndex index.php这行下面增加以下两行
						    RewriteEngine On
						    RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization},last]
			*/
			if (isset($_SERVER['HTTP_AUTHORIZATION'])) {
				$authorizationBase64 = $_SERVER['HTTP_AUTHORIZATION'];
			}
			if (isset($_SERVER['HTTP_X_OSS_PUB_KEY_URL'])) {
				$pubKeyUrlBase64 = $_SERVER['HTTP_X_OSS_PUB_KEY_URL'];
			}

			if ($authorizationBase64 == '' || $pubKeyUrlBase64 == '') {
				header("http/1.1 403 Forbidden");
				exit();
			}

			// 2.获取OSS的签名
			$authorization = base64_decode($authorizationBase64);

			// 3.获取公钥
			$pubKeyUrl = base64_decode($pubKeyUrlBase64);
			$ch = curl_init();
			curl_setopt($ch, CURLOPT_URL, $pubKeyUrl);
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
			curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
			$pubKey = curl_exec($ch);

			if ($pubKey == "") {
				//header("http/1.1 403 Forbidden");
				return json(['code' => 0, 'msg' => "获取公钥失败!"]);
				exit();
			}

			// 4.获取回调body
			$body = file_get_contents('php://input');
			$data = $this->request->param();

			file_put_contents("./console.log", date("Y-m-d H:i:s") . ": " . $body . "\r\n\r\n", FILE_APPEND);

			// 5.拼接待签名字符串
			$authStr = '';
			$path = $_SERVER['REQUEST_URI'];
			$pos = strpos($path, '?');
			if ($pos === false) {
				$authStr = urldecode($path) . "\n" . $body;
			} else {
				$authStr = urldecode(substr($path, 0, $pos)) . substr($path, $pos, strlen($path) - $pos) . "\n" . $body;
			}

			// 6.验证签名
			$ok = openssl_verify($authStr, $authorization, $pubKey, OPENSSL_ALGO_MD5);
			if ($ok == 1) {
				$findAsset = Db::name('asset')->where('file_key', $data['etag'])->find();
				$arr = explode('/', $data['filename']);
				$filename = array_pop($arr);
				if (empty($findAsset)) {
					/************  拼接url  ************/
					$aliyuncsPlugin = new AliyuncsPlugin();
					$config = $aliyuncsPlugin->getConfig();
					if (!empty($config['domain']) && strpos($config['domain'], 'http') !== false) {
						$fileurl = rtrim($config['domain'], "/") . "/" . $data['filename'];
					} else {
						$fileurl = $config['protocol'] . '://' . $config['bucket'] . '.' . $config['endpoint'] . "/" . $data['filename'];
					}
					//获取文件名
					/************  拼接url  ************/
					$suffix = strtolower(cmf_get_file_extension($filename));
					Db::name('asset')->insert([
						'user_id' => $data['uid'],
						'file_size' => $data['size'],
						'filename' => $filename,
						'create_time' => time(),
						'file_key' => $data['etag'],
						'file_path' => $fileurl,
						'suffix' => $suffix,
					]);
				}else{
					$fileurl = $findAsset['file_path'];
				}

				$new_data = [
					'filepath' => $fileurl,
					'name' => $filename,
					'preview_url' => cmf_get_image_preview_url($fileurl),
					'url' => $fileurl,
				];
				$return_data = ['code' => 1, "Status" => "Ok", "msg" => "上传成功!", "data" => $new_data];
				ob_clean();
				header("Content-Type: application/json");
				return json($return_data);
			} else {
				//header("http/1.1 403 Forbidden");
				return json(['code' => 0, 'msg' => "验签失败!"]);
				exit();
			}

		} catch (\Exception $e) {
			$str = "发生错误: " . date("Y-m-d H:i:s") . "\r\n";
			$str .= "Error: " . $e->getMessage() . "行号: #" . $e->getLine() . "\r\n\r\n";

			file_put_contents("./console.log", $str, FILE_APPEND);
			return json(['code' => 0, 'msg' => $str]);
		}
	}
}
